/*This file is part of PaperBall.

PaperBall is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

PaperBall is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with PaperBall.  If not, see <http://www.gnu.org/licenses/>.*/

package com.ran3000.paperball;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.ran3000.paperball.framework.math.OverlapTester;
import com.ran3000.paperball.framework.math.Vector2;

public class World {
	public interface WorldListener {
		public void explode();
	}
	
	public static final float WORLD_WIDTH = 15;
	public static final float WORLD_HEIGHT = 10;
	public static final int WORLD_STATE_RUNNING = 0;
	public static final int WORLD_STATE_GAME_OVER = 1;
	public static final Vector2 gravity = new Vector2(0, -10);
	
	public final Ball ball;
	public final List<Bomb> bombs;
	public final List<Explosion> explosions;
	public final List<Shield> shields;
	public final WorldListener listener;
	public final Random rand;
	
	public int score;
	public int state;
	
	public int nBombs;
	
	public float bombX;
	public static final float bombY = 11.2f;
	
	public World(WorldListener listener) {
		rand = new Random();
		this.ball = new Ball(5);
		this.bombs = new ArrayList<Bomb>();
		this.explosions = new ArrayList<Explosion>();
		this.shields = new ArrayList<Shield>();
		this.listener = listener; 
		generateLevel();
		
		this.score = 0;
		this.state = WORLD_STATE_RUNNING;
		this.nBombs = 3;
		
	}
	
	private void generateLevel() {
		while (bombs.size() < nBombs) {
			
			bombX = rand.nextFloat() * (WORLD_WIDTH - Bomb.BOMB_RADIUS) + Bomb.BOMB_RADIUS;
			Bomb bomb = new Bomb(bombX, bombY);
			bombs.add(bomb);
		}
	}
	
	public void update(float deltaTime, float accelY) {
		updateBall(deltaTime, accelY);
		updateBombs(deltaTime);
		updateExplosions(deltaTime);
		updateShield();
		updateIce(deltaTime);
		checkCollisions();
	}
	
	private void updateShield() {
		if(rand.nextFloat() > 0.998f) {
			Shield shield = new Shield(rand.nextFloat() * WORLD_WIDTH);				
			shields.add(shield);
		}
		
		 for(int i = 0; i < shields.size(); i++) {
			 if(ball.state == Ball.BALL_STATE_SHIELDED) {
				 Shield shield = shields.get(i);
				 shield.position.set(ball.position);
			 }
		}
	}
	
	private void updateBall(float deltaTime, float accelY) {
		
		ball.velocity.x = accelY / 10 * Ball.BALL_MOVE_VELOCITY;
		
		if(ball.position.x < 0){
			ball.position.x = WORLD_WIDTH;
		}
		if(ball.position.x > WORLD_WIDTH){
			ball.position.x = 0;
		}
		
		ball.update(deltaTime);
	}

	
	private void updateBombs(float deltaTime) {
		
		int len = bombs.size();
		for(int i = 0; i < len; i++) {
			Bomb bomb = bombs.get(i);
			bomb.update(deltaTime);
			if(bomb.state == Bomb.BOMB_EXPLODED) {
				score += Bomb.BOMB_SCORE;
				Explosion explosion = new Explosion(bomb.position.x, bomb.position.y);
				explosions.add(explosion);
				listener.explode();
				bombs.remove(bomb);
				len = bombs.size();
				break;
			}
		}
		
		if(bombs.size() < nBombs) {
			Bomb bomb = new Bomb(rand.nextFloat() * (WORLD_WIDTH - Bomb.BOMB_RADIUS) + Bomb.BOMB_RADIUS, bombY);
			bombs.add(bomb);
		}
	}
	
	private void updateExplosions(float deltaTime) {
		int len = explosions.size();
		for(int i = 0; i < len; i++) {
			Explosion explosion = explosions.get(i);
			explosion.update(deltaTime);
		}
	}
	
	private void updateIce(float deltaTime) {
		
	}
	
	private void checkCollisions() {
		checkBombCollision();
		checkShieldCollision();
	}
	
	private void checkBombCollision() {
		int len = bombs.size();
		for(int i = 0; i < len; i++) {
			Bomb bomb = bombs.get(i);
			if(OverlapTester.overlapCircles(ball.bounds, bomb.bounds)) {
				if(ball.state == Ball.BALL_STATE_NORMAL) {
					ball.hitBomb();
					bomb.state = Bomb.BOMB_EXPLODED;
					Explosion explosion = new Explosion(ball.position.x, ball.position.y);
					explosions.add(explosion);
					listener.explode();
					state = WORLD_STATE_GAME_OVER;
					break;
				} else {
					bomb.state = Bomb.BOMB_EXPLODED;
					Explosion explosion = new Explosion(ball.position.x, ball.position.y);
					explosions.add(explosion);
					listener.explode();
					ball.state = Ball.BALL_STATE_NORMAL;
					for(int j = 0; j < shields.size(); j++) {
						shields.remove(j);
					}
					break;
				}
			}
		}
	}
	
	private void checkShieldCollision() {
		int len = shields.size();
		for(int i = 0; i < len; i++) {
			Shield shield = shields.get(i);
			if(OverlapTester.overlapCircleRectangle(ball.bounds, shield.bounds)){
					ball.state = Ball.BALL_STATE_SHIELDED;
			}
		}
	}
}
